package it.trekker.activities;

import java.io.File;
import java.io.IOException;

import it.trekker.R;
import it.trekker.camera.UtilityCamera;
import it.trekker.db.Excursion;
import it.trekker.db.ExcursionDAO;
import it.trekker.db.ExcursionTableMeta;
import it.trekker.db.PhotoDAO;
import it.trekker.dialogs.NewExcursionDialog;
import it.trekker.gps.service.GPSDataCollector;
import it.trekker.gps.service.GPSLocationService;
import it.trekker.upload.UploadHelper;
import it.trekker.upload.UploadHelperMultipart;
import it.trekker.upload.UploadHelperRest;
import it.trekker.upload.User;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.CursorAdapter;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;

public class ExcursionsListViewActivity extends ListActivity implements NewExcursionDialog.INewExcursion {

	private static final String TAG = ExcursionsListViewActivity.class.getSimpleName();

	// GUI components
	private ListView excursionsListView = null;
	private ImageButton newExcursion_bt = null;
	private ImageButton upload_bt = null;
//	private ProgressDialog progressDialog = null;

	private Cursor data = null;
	private CursorAdapter dataSource = null;
	private Context ctx = null;
	private ExcursionDAO excursionDAO = null;
	private Excursion excursion;
	//	private boolean newExcursionStarted = false;
	
	private UploadHelper uploadHelper;

	// Service components
	private GPSDataCollector gpsDataCollector;
	private GPSLocationService gpsLocationService = null;
	private ServiceConnection serviceConnection = new ServiceConnection() {
		@Override
		public void onServiceDisconnected(ComponentName name) {
			gpsLocationService = null;
			excursion = null;
		}

		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			gpsLocationService = ((GPSLocationService.GPSBinder)service).getService();
			gpsDataCollector.startDataCollecting(excursion.getName());
			gpsLocationService.addGPSListener(gpsDataCollector);
		}
	};

	@Override
	protected void onCreate(Bundle savedInstanceState) {

		Log.d(TAG, "onCreate");

		super.onCreate(savedInstanceState);
		ctx = this;
		
		setContentView(R.layout.excursions_listview_layout);

		// Restore objects created before configuration change

		SavedObjects saved = (SavedObjects) getLastNonConfigurationInstance();
		if(saved != null) {
			serviceConnection = saved.serviceConnection;
			gpsLocationService = saved.gpsLocationService;
			gpsDataCollector = saved.gpsDataCollector;
		}
		else {
			gpsDataCollector = new GPSDataCollector(this);
		}
		
		uploadHelper = new UploadHelperRest(ctx);

		// Normal initialization

		excursionDAO = new ExcursionDAO(this);

		excursionsListView = getListView();
		
		newExcursion_bt = (ImageButton) findViewById(R.id.btn_new_excursion);
		newExcursion_bt.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				showCreateNewExcursionDialog();
			}
		});
		
		upload_bt = (ImageButton) findViewById(R.id.btn_upload);
		upload_bt.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				uploadData();
			}
		});
	}


	@Override
	protected void onResume() {
		super.onResume();

		Log.d(TAG, "onResume");

		//		progressDialog = ProgressDialog.show(this, "Working..." , "Loading excursions");
		//		runOnUiThread(new LoadDataThread());

		new AsyncLoading().execute();
	}


	@Override
	protected void onPause() {
		super.onPause();

		Log.d(TAG, "onPause");

		excursionDAO.close();
		data.close();
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();

		Log.d(TAG, "onDestroy");

		//		if(newExcursionStarted) {
		//			stopExcursion();
		//		}
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);

		Log.d(TAG, "onSaveInstanceState");

		//		outState.putBoolean("newExcursionStarted", newExcursionStarted);
	}

	@Override
	protected void onRestoreInstanceState(Bundle state) {
		super.onRestoreInstanceState(state);

		Log.d(TAG, "onRestoreInstanceState");

		//		newExcursionStarted = state.getBoolean("newExcursionStarted");
	}

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);

		Log.d(TAG, "onConfigurationChanged");
	}


	// Save objects to reload after a configuration changed

	private class SavedObjects {
		public ServiceConnection serviceConnection;
		public GPSLocationService gpsLocationService;
		public GPSDataCollector gpsDataCollector;
	}
	@Override
	public Object onRetainNonConfigurationInstance() {
		Log.d(TAG, "onRetainNonConfigurationInstance");

		SavedObjects saved = new SavedObjects();

		saved.serviceConnection = serviceConnection;
		saved.gpsLocationService = gpsLocationService;
		saved.gpsDataCollector = gpsDataCollector;

		return saved;
	}





	//***********************************************************//
	//*********************** Option Menu ***********************//
	//***********************************************************//

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		menu.clear();
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.excursions_list_menu, menu);

		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle item selection
		switch (item.getItemId()) {

		case R.id.new_excursion:
			showCreateNewExcursionDialog();
			return true;

		default:
			return super.onOptionsItemSelected(item);
		}
	}





	//**********************************************************//
	//********************** Context Menu **********************//
	//**********************************************************//

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {

		AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;

		data.moveToPosition(info.position);
		String excursionName = data.getString(data.getColumnIndex(ExcursionTableMeta.KEY_NAME));

		menu.setHeaderTitle(excursionName);

		String[] menuItems = getResources().getStringArray(R.array.excursion_contextmenu);		
		for (int i = 0; i<menuItems.length; i++) {
			menu.add(Menu.NONE, i, i, menuItems[i]);
		}
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {

		AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();
		int menuItemIndex = item.getItemId();
		data.moveToPosition(info.position);

		switch(menuItemIndex) {

		case 0:		// Show GPS points
			lounchActivity(CoordinatesListViewActivity.class);
			break;

		case 1:		// Show map
			lounchActivity(ExcursionMapActivity.class);
			break;

		case 2:		// Show statistics
			lounchActivity(ExcursionStatisticsActivity.class);
			break;

		case 3:		// Delete
			deleteExcursion();
			break;
		}

		return true;
	}





	//***********************************************************//
	//************************* Dialogs *************************//
	//***********************************************************//


	private static final int DIALOG_NEWEXCURSION = 0;

	private void showCreateNewExcursionDialog() {
		showDialog(DIALOG_NEWEXCURSION);
	}

	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dialog;

		switch(id) {
		case DIALOG_NEWEXCURSION:
			dialog = createNewExcursionDialog();
			break;

		default:
			dialog = null;
		}

		return dialog;
	}

	private NewExcursionDialog createNewExcursionDialog() {
		return new NewExcursionDialog(this);
	}






	//*******************************************************************//
	//*********************** Utilities functions ***********************//
	//*******************************************************************//

	private void lounchActivity(Class activityClass) {
		int excursionId = data.getInt(data.getColumnIndex(ExcursionTableMeta.KEY_ROWID));
		Intent intent = new Intent(this, activityClass);
		intent.putExtra("excursion_id", excursionId);

		startActivity(intent);
	}

	private void deleteExcursion() {
		final long excursionId = data.getInt(data.getColumnIndex(ExcursionTableMeta.KEY_ROWID));

		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setMessage("Do you also want delete photos?")
		.setCancelable(false)
		.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int id) {
//				progressDialog = ProgressDialog.show(getContext(), "Deleting...", "Deleting photos");
//				runOnUiThread(new DeleteExcursionWithFileThread(excursionId));
				new AsyncDeleting().execute(excursionId);
			}
		})
		.setNegativeButton("No", new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int id) {
				excursionDAO.deleteExcursion(excursionId);
				updateExcursionsListView();
				dialog.cancel();
			}
		});
		AlertDialog alert = builder.create();
		alert.show();
	}

	@Override
	public void createNewExcursion(String name) {
		//		excursion = new Excursion(name);
		//		
		//		Intent intent = new Intent(this, GPSLocationService.class);
		//		getApplicationContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
		//
		//		newExcursionStarted = true;
		//		
		//		updateExcursionsListView();

		ExcursionsListViewActivity.this.finish();

		Intent intentNewExcursion = new Intent(this, ExcursionMainActivity.class);
		intentNewExcursion.putExtra("excursion_name", name);
		startActivity(intentNewExcursion);

		//		newExcursionStarted = true;
	}


	@Override
	public Context getContext() {
		return this;
	}


	private void loadData() {
		excursionDAO.open();
		data = excursionDAO.getAllExcursionsAsCursor();
	}


	private void updateViews() {

		if(data.getCount() == 0) {
			String[] messages = new String[1];
			ArrayAdapter<String> itemAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, messages);
			excursionsListView.setAdapter(itemAdapter);

			messages[0] = getString(R.string.no_excursions);
			itemAdapter.notifyDataSetChanged();
		}
		else {
			String[] from = {ExcursionTableMeta.KEY_NAME, ExcursionTableMeta.KEY_DATE};
			int[] to = {R.id.excursion_name, R.id.excursion_date};

			dataSource = new SimpleCursorAdapter(this, R.layout.excursions_listview_row, data, from, to);

			setListAdapter(dataSource);

			excursionsListView.setOnItemClickListener(new ItemSelectedListener());
			registerForContextMenu(excursionsListView);
		}
	}


	private void updateExcursionsListView() {
		data.close();
		data = excursionDAO.getAllExcursionsAsCursor();
		if(data.getCount() == 0) {
			String[] messages = new String[1];
			ArrayAdapter<String> itemAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, messages);
			excursionsListView.setAdapter(itemAdapter);

			messages[0] = getString(R.string.no_excursions);
			itemAdapter.notifyDataSetChanged();

			unregisterForContextMenu(excursionsListView);
			excursionsListView.setOnItemClickListener(null);
		}
		else {
			dataSource.changeCursor(data);
			dataSource.notifyDataSetChanged();
		}
	}


	private void uploadData() {
		User user = loadUserFromPreferences();
		String serverUrl = loadServerUrlFromPreferences();
		new AsyncUpload().execute(user, serverUrl);
	}
	
	
	private User loadUserFromPreferences() {
		SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
		User user = new User();
		
		user.setUsername(sharedPref.getString("pref_username", getString(R.string.default_user)));
		
		return user;
	}
	
	
	private String loadServerUrlFromPreferences() {
		SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
		
		return sharedPref.getString("pref_server_url", "");
	}




	//****************************************************************//
	//*********************** Listener classes ***********************//
	//****************************************************************//


	private class ItemSelectedListener implements AdapterView.OnItemClickListener {

		@Override
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
			//			int excursionId = Integer.parseInt(((TextView)view.findViewById(R.id.excursion_id)).getText().toString());
			data.moveToPosition(position);
			int excursionId = data.getInt(data.getColumnIndex(ExcursionTableMeta.KEY_ROWID));
			//			Intent intent = new Intent(ctx, CoordinatesListViewActivity.class);
			Intent intent = new Intent(ctx, ExcursionMapActivity.class);
			intent.putExtra("excursion_id", excursionId);

			startActivity(intent);
		}

	}






	//***********************************************************************//
	//****************** Loading data thread and utilities ******************//
	//***********************************************************************//


//	private static final int LOAD_END = 0;
//	private static final int DELETE_END = 1;

//	private Handler handler = new Handler() {
//		@Override
//		public void handleMessage(Message msg) {
//			switch(msg.what) {
//			case LOAD_END:	
//				progressDialog.dismiss();
//				updateViews();
//				break;
//			case DELETE_END:	
//				progressDialog.dismiss();
//				updateExcursionsListView();
//				break;
//			default:
//				super.handleMessage(msg);
//				break;
//			}
//		};
//	};


//	private class LoadDataThread implements Runnable {
//		@Override
//		public void run() {
//			loadData();
//			handler.sendEmptyMessage(LOAD_END);
//		}
//	}


//	private class DeleteExcursionWithFileThread implements Runnable {
//		private long excursionId;
//
//		public DeleteExcursionWithFileThread(long excursionId) {
//			this.excursionId = excursionId;
//		}
//
//		@Override
//		public void run() {
//			PhotoDAO photoDAO = new PhotoDAO(getContext());
//			photoDAO.open();
//			photoDAO.deleteAllPhotosByExcursion(excursionId, true);
//			photoDAO.close();
//
//			excursionDAO.deleteExcursion(excursionId);
//
//			UtilityCamera.updateGallery(ExcursionsListViewActivity.this);
//
//			handler.sendEmptyMessage(DELETE_END);
//		}
//
//	}




	private class AsyncLoading extends AsyncTask<Void, Void, Boolean> {

		private ProgressDialog progressDialog;

		@Override
		protected void onPreExecute() {
			progressDialog = ProgressDialog.show(ExcursionsListViewActivity.this, getString(R.string.working) , getString(R.string.loading_excursions));
		}

		@Override
		protected Boolean doInBackground(Void... params) {

			excursionDAO.open();
			data = excursionDAO.getAllExcursionsAsCursor();

			return true;
		}

		@Override
		protected void onPostExecute(Boolean result) {
			updateViews();
			progressDialog.dismiss();
		}

	}


	private class AsyncDeleting extends AsyncTask<Long, Integer, Boolean> {

		private ProgressDialog progressDialog;

		@Override
		protected void onPreExecute() {
			progressDialog = ProgressDialog.show(getContext(), getString(R.string.working), getString(R.string.deleting_photos));
		}

		@Override
		protected Boolean doInBackground(Long... params) {

			PhotoDAO photoDAO = new PhotoDAO(getContext());
			photoDAO.open();
			photoDAO.deleteAllPhotosByExcursion(params[0], true);
			photoDAO.close();

			excursionDAO.deleteExcursion(params[0]);

			UtilityCamera.updateGallery(ExcursionsListViewActivity.this);

			return true;
		}

		@Override
		protected void onPostExecute(Boolean result) {
			updateExcursionsListView();
			progressDialog.dismiss();
		}

	}
	
	
	private class AsyncUpload extends AsyncTask<Object, Integer, Boolean> {

		private ProgressDialog progressDialog;

		@Override
		protected void onPreExecute() {
			progressDialog = ProgressDialog.show(getContext(), getString(R.string.working), getString(R.string.creating_file));
		}

		@Override
		protected Boolean doInBackground(Object... params) {
			Looper.prepare();
			
			boolean result = false;
			
			try {
				User user = (User) params[0];
				String serverUrl = (String) params[1];
				
//				String filePath = uploadHelper.export2XmlFile(user);
				String filePath = uploadHelper.export2JsonFile(user);
				publishProgress(50);
				result = uploadHelper.uploadFile(filePath, serverUrl);
				
				File file = new File(filePath);
				file.delete();
				
			} catch (IOException e) {
				e.printStackTrace();
			}

			return result;
		}

		@Override
		protected void onPostExecute(Boolean result) {
			progressDialog.dismiss();
			
			if(result)
				Toast.makeText(getContext(), R.string.upload_successful, Toast.LENGTH_LONG).show();
			else
				Toast.makeText(getContext(), R.string.upload_failed, Toast.LENGTH_LONG).show();
		}
		
		@Override
		protected void onProgressUpdate(Integer... values) {
			progressDialog.setMessage(getString(R.string.uploading_data));
		}

	}
}
